import pinia from "/@/stores/index";
import { RouteRecordRaw } from "vue-router";
import { formatTwoStageRoutes, formatFlatteningRoutes, router } from "/@/router/index";
import { dynamicRoutes, warningRoutes } from "/@/router/route";
import { storeToRefs } from "pinia";
import { useThemeConfig } from "/@/stores/themeConfig";
import { useUserInfo } from "/@/stores/userInfo";
import { useTagsViewRoutes } from "/@/stores/tagsViewRoutes";
import { useRoutesList } from "/@/stores/routesList";
import { NextLoading } from "/@/utils/loading";
import { getMockRouters } from "/@/api/menu";

// 读取 `/src/stores/themeConfig.ts` 是否开启后端控制路由配置
const { themeConfig } = storeToRefs(useThemeConfig(pinia));
const { isRequestRoutes } = themeConfig.value;

/**
 * 路由初始化
 * @method NextLoading 界面 loading 动画开始执行
 * @method useUserInfo().getUserInfo() 初始化 pinia 的用户信息
 * @method addRoute 添加路由到路由表中（固定角色权限控制路由）
 * @method addDynamicRoute 添加路由到路由表中（动态角色权限控制路由）
 * @method setFilterMenuAndCacheTagsViewRoutes 缓存有权限的路由 & 缓存多级嵌套数组处理后的一维数组
 * @method setDynamicFilterMenuAndCacheTagsViewRoutes 缓存有权限的路由 & 缓存多级嵌套数组处理后的一维数组
 */
export async function initFrontEndControlRoutes() {
	// 界面 loading 动画开始执行
	if (window.nextLoading === undefined) NextLoading.start();
	// 初始化 pinia 的用户信息，并获取用户角色数据
	const { roles = [] } = await useUserInfo().getUserInfo();
	// 判断用户有无系统访问权限（没分配角色的用户无权访问）
	if (roles.length === 0) return Promise.reject("抱歉，您没有权限访问该系统");
	if (isRequestRoutes) {
		// 获取用户角色对应的路由数据
		const { code, data } = await getMockRouters({ roles });
		if (code !== 200) return Promise.reject("路由数据获取失败，请重新登录");
		// 添加路由到路由表中（动态角色权限控制路由）
		addDynamicRoute(data);
		// 缓存有权限的路由 & 缓存多级嵌套数组处理后的一维数组
		setDynamicFilterMenuAndCacheTagsViewRoutes(data);
	} else {
		// 添加路由到路由表中（固定角色权限控制路由）
		addRoute();
		// 缓存有权限的路由 & 缓存多级嵌套数组处理后的一维数组
		setFilterMenuAndCacheTagsViewRoutes();
	}
}

/**
 * 添加路由
 * @param routeIds 路由 id 数组
 * @method router.addRoute
 */
export function addDynamicRoute(routeIds: string[]) {
	const filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
	const filterRoutes: any[] = [];
	// 根据 routeIds 过滤路由
	const children = filterRouteEnd[0].children;
	routeIds.forEach(id => {
		for (let i = 0; i < children.length; i++) {
			if (children[i].meta.id === id) {
				children[i].children = [];
				filterRoutes.push({ ...children[i] });
				break;
			}
		}
	});
	// 把过滤后的路由添加到路由表中
	filterRouteEnd[0].children = [...filterRoutes, ...warningRoutes];
	filterRouteEnd.forEach((route: RouteRecordRaw) => {
		router.addRoute(route);
	});
}

/**
 * 添加路由
 * @method router.addRoute
 */
export async function addRoute() {
	await setFilterRouteEnd().forEach((route: RouteRecordRaw) => {
		router.addRoute(route);
	});
}

/**
 * 移除路由
 * @method router.removeRoute
 */
export async function removeRoute() {
	await setFilterRouteEnd().forEach((route: RouteRecordRaw) => {
		const routeName: any = route.name;
		router.hasRoute(routeName) && router.removeRoute(routeName);
	});
}

/**
 * 获取有当前用户权限标识的路由数组，进行对原路由的替换
 * @description 替换 dynamicRoutes（/@/router/route）第一个顶级 children 的路由
 * @returns 返回替换后的路由数组
 */
export function setFilterRouteEnd() {
	let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
	// 添加 warningRoutes 防止 404、401 不在 layout 布局中，否则 404、401 界面将全屏显示
	filterRouteEnd[0].children = [...setFilterRoute(filterRouteEnd[0].children), ...warningRoutes];
	return filterRouteEnd;
}

/**
 * 获取当前用户权限标识去比对路由表（未处理成多级嵌套路由）
 * @param chil dynamicRoutes（/@/router/route）第一个顶级 children 的下路由集合
 * @returns 返回有当前用户权限标识的路由数组
 */
export function setFilterRoute(chil: any) {
	const { userInfo } = storeToRefs(useUserInfo());
	let filterRoute: any = [];
	chil.forEach((route: any) => {
		if (route.meta.roles) {
			route.meta.roles.forEach((metaRoles: any) => {
				userInfo.value.roles.forEach((roles: any) => {
					if (metaRoles === roles) filterRoute.push({ ...route });
				});
			});
		}
	});
	return filterRoute;
}

/**
 * 缓存有权限的路由 & 缓存多级嵌套数组处理后的一维数组
 * @param routeIds 路由 id 数组
 */
export function setDynamicFilterMenuAndCacheTagsViewRoutes(routeIds: string[]) {
	// 缓存到 pinia routesList 中（用于左侧菜单、横向菜单的显示，未过滤隐藏的路由）
	const storesRoutesList = useRoutesList();
	const temp1 = setFilterHasIdsMenu(dynamicRoutes[0].children!, routeIds);
	storesRoutesList.setRoutesList(temp1);
	// 缓存到 pinia tagsViewRoutes 中（用于菜单搜索、tagsView 的显示，未过滤隐藏的路由）
	const storesTagsView = useTagsViewRoutes();
	const temp2 = setFilterHasIdsMenu(dynamicRoutes, routeIds);
	storesTagsView.setTagsViewRoutes(formatTwoStageRoutes(formatFlatteningRoutes(temp2))[0].children);
}

/**
 * 缓存有权限的路由 & 缓存多级嵌套数组处理后的一维数组
 */
export function setFilterMenuAndCacheTagsViewRoutes() {
	const storesRoutesList = useRoutesList();
	const { userInfo } = storeToRefs(useUserInfo());
	// 缓存到 pinia routesList 中
	storesRoutesList.setRoutesList(setFilterHasRolesMenu(dynamicRoutes[0].children, userInfo.value.roles));
	setCacheTagsViewRoutes();
}

/**
 * 缓存多级嵌套数组处理后的一维数组
 */
export function setCacheTagsViewRoutes() {
	const storesTagsView = useTagsViewRoutes();
	const { userInfo } = storeToRefs(useUserInfo());
	const rolesRoutes = setFilterHasRolesMenu(dynamicRoutes, userInfo.value.roles);
	// 缓存到 pinia tagsViewRoutes 中
	storesTagsView.setTagsViewRoutes(formatTwoStageRoutes(formatFlatteningRoutes(rolesRoutes))[0].children);
}

/**
 * 判断路由 `meta.roles` 中是否包含当前登录用户权限字段
 * @param route 当前循环时的路由数据
 * @param roles 用户权限标识，在 userInfo（用户信息）的 roles 数组
 * @returns 返回布尔值
 */
export function hasRoles(route: any, roles: any) {
	if (route.meta && route.meta.roles) return roles.some((role: any) => route.meta.roles.includes(role));
	else return true;
}

/**
 * 获取当前用户权限标识去比对路由表，递归过滤有权限的路由
 * @param routes 路由数据
 * @param roles 用户权限标识，在 userInfo（用户信息）的 roles 数组
 * @returns 返回有权限的路由数组
 */
export function setFilterHasRolesMenu(routes: any, roles: any) {
	const menu: any = [];
	routes.forEach((route: any) => {
		const item = { ...route };
		if (hasRoles(item, roles)) {
			if (item.children) item.children = setFilterHasRolesMenu(item.children, roles);
			menu.push(item);
		}
	});
	return menu;
}

/**
 * 根据路由权限数据，递归过滤有权限的路由
 * @param routes 路由数据
 * @param routeIds 路由权限数据
 * @returns 返回有权限的路由数组
 */
export function setFilterHasIdsMenu(routes: RouteRecordRaw[], routeIds: string[]) {
	const menu: RouteRecordRaw[] = [];
	routes.forEach((route: RouteRecordRaw) => {
		const item = { ...route };
		if (item.path === "/" || routeIds.includes(item.meta!.id)) {
			if (item.children) item.children = setFilterHasIdsMenu(item.children, routeIds);
			menu.push(item);
		}
	});
	return menu;
}
